{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:11:08.808307Z",
     "start_time": "2022-01-21T12:10:59.351309Z"
    }
   },
   "outputs": [],
   "source": [
    "import tensorflow as tf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:13:30.076927Z",
     "start_time": "2022-01-21T12:13:30.052990Z"
    }
   },
   "outputs": [],
   "source": [
    "# 把ragged constant转化成普通的tensor\n",
    "r = tf.ragged.constant([[1, 2, 3], [1], [], [1, 2, 3, 4, 5]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:14:53.850523Z",
     "start_time": "2022-01-21T12:14:53.828582Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(4, 3), dtype=int32, numpy=\n",
       "array([[1, 2, 3],\n",
       "       [1, 1, 1],\n",
       "       [1, 1, 1],\n",
       "       [1, 2, 3]])>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 对不齐的地方补0, 可以通过default_value指定填充的值. shape可以指定转化之后的形状, 多余部分会被截断.\n",
    "r.to_tensor(default_value=1, shape=(4, 3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:29:12.131799Z",
     "start_time": "2022-01-21T12:29:12.115840Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "SparseTensor(indices=tf.Tensor(\n",
       "[[0 1]\n",
       " [1 0]\n",
       " [2 3]], shape=(3, 2), dtype=int64), values=tf.Tensor([4 5 6], shape=(3,), dtype=int32), dense_shape=tf.Tensor([3 4], shape=(2,), dtype=int64))"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 稀疏tensor, 稀疏矩阵, sparse tensor\n",
    "# 矩阵中0的元素多于非0的元素, 非0元素的排列是没有规律.\n",
    "# indices表示哪些位置上是非零0, \n",
    "# values指具体是哪些值\n",
    "# dense_shape即sparsetensor的shape\n",
    "s = tf.SparseTensor(indices=[[0, 1], [1, 0], [2, 3]], values=[4, 5, 6], dense_shape=[3, 4])\n",
    "s"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:26:49.185242Z",
     "start_time": "2022-01-21T12:26:49.118419Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'SparseTensor(indices=tf.Tensor(\\n[[0 1]\\n [1 0]\\n [2 3]], shape=(3, 2), dtype=int64), values=tf.Tensor([4 5 6], shape=(3,), dtype=int32), dense_shape=tf.Tensor([3 4], shape=(2,), dtype=int64))'"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.__str__()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:29:14.848630Z",
     "start_time": "2022-01-21T12:29:14.836662Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "SparseTensor(indices=tf.Tensor(\n",
      "[[0 1]\n",
      " [1 0]\n",
      " [2 3]], shape=(3, 2), dtype=int64), values=tf.Tensor([4 5 6], shape=(3,), dtype=int32), dense_shape=tf.Tensor([3 4], shape=(2,), dtype=int64))\n"
     ]
    }
   ],
   "source": [
    "print(s)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:30:08.256716Z",
     "start_time": "2022-01-21T12:30:08.140027Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(3, 4), dtype=int32, numpy=\n",
       "array([[0, 4, 0, 0],\n",
       "       [5, 0, 0, 0],\n",
       "       [0, 0, 0, 6]])>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 变成稠密矩阵\n",
    "tf.sparse.to_dense(s)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:31:53.449647Z",
     "start_time": "2022-01-21T12:31:53.403770Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "SparseTensor(indices=tf.Tensor(\n",
       "[[0 1]\n",
       " [1 0]\n",
       " [2 3]], shape=(3, 2), dtype=int64), values=tf.Tensor([ 8 10 12], shape=(3,), dtype=int32), dense_shape=tf.Tensor([3 4], shape=(2,), dtype=int64))"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 可以做乘法.\n",
    "s * 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:32:05.650885Z",
     "start_time": "2022-01-21T12:32:04.916329Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "unsupported operand type(s) for +: 'SparseTensor' and 'int'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-20-b8bba336fa32>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0ms\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'SparseTensor' and 'int'"
     ]
    }
   ],
   "source": [
    "# 不能做加法\n",
    "s + 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:34:45.076800Z",
     "start_time": "2022-01-21T12:34:44.998010Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(3, 2), dtype=int32, numpy=\n",
       "array([[120, 160],\n",
       "       [ 50, 100],\n",
       "       [420, 480]])>"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# matmul matrix multiply\n",
    "# (3, 4), (4, x)\n",
    "ss = tf.constant([[10, 20],\n",
    "            [30, 40],\n",
    "            [50, 60],\n",
    "            [70, 80]])\n",
    "tf.sparse.sparse_dense_matmul(s, ss)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:36:44.331101Z",
     "start_time": "2022-01-21T12:36:44.323122Z"
    }
   },
   "outputs": [],
   "source": [
    "# 定义sparse_tensor的时候, indices最好是有序的.\n",
    "s2 = tf.SparseTensor(indices=[[0, 2], [0, 1], [2, 3]], values=[1, 2, 3], dense_shape=[3, 4])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:36:49.332894Z",
     "start_time": "2022-01-21T12:36:49.314942Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "SparseTensor(indices=tf.Tensor(\n",
      "[[0 2]\n",
      " [0 1]\n",
      " [2 3]], shape=(3, 2), dtype=int64), values=tf.Tensor([1 2 3], shape=(3,), dtype=int32), dense_shape=tf.Tensor([3 4], shape=(2,), dtype=int64))\n"
     ]
    }
   ],
   "source": [
    "print(s2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:37:12.826227Z",
     "start_time": "2022-01-21T12:37:12.619779Z"
    },
    "collapsed": true
   },
   "outputs": [
    {
     "ename": "InvalidArgumentError",
     "evalue": "indices[1] = [0,1] is out of order. Many sparse ops require sorted indices.\n    Use `tf.sparse.reorder` to create a correctly ordered copy.\n\n [Op:SparseToDense]",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mInvalidArgumentError\u001b[0m                      Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-24-f550a6871c98>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# 转化成稠密矩阵\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mtf\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msparse\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mto_dense\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0ms2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;32md:\\2005\\.venv\\lib\\site-packages\\tensorflow\\python\\ops\\sparse_ops.py\u001b[0m in \u001b[0;36msparse_tensor_to_dense\u001b[1;34m(sp_input, default_value, validate_indices, name)\u001b[0m\n\u001b[0;32m   1647\u001b[0m       \u001b[0mdefault_value\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mdefault_value\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1648\u001b[0m       \u001b[0mvalidate_indices\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mvalidate_indices\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1649\u001b[1;33m       name=name)\n\u001b[0m\u001b[0;32m   1650\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1651\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32md:\\2005\\.venv\\lib\\site-packages\\tensorflow\\python\\ops\\gen_sparse_ops.py\u001b[0m in \u001b[0;36msparse_to_dense\u001b[1;34m(sparse_indices, output_shape, sparse_values, default_value, validate_indices, name)\u001b[0m\n\u001b[0;32m   3159\u001b[0m       \u001b[1;32mreturn\u001b[0m \u001b[0m_result\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   3160\u001b[0m     \u001b[1;32mexcept\u001b[0m \u001b[0m_core\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_NotOkStatusException\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 3161\u001b[1;33m       \u001b[0m_ops\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mraise_from_not_ok_status\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0me\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mname\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   3162\u001b[0m     \u001b[1;32mexcept\u001b[0m \u001b[0m_core\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_FallbackException\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   3163\u001b[0m       \u001b[1;32mpass\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32md:\\2005\\.venv\\lib\\site-packages\\tensorflow\\python\\framework\\ops.py\u001b[0m in \u001b[0;36mraise_from_not_ok_status\u001b[1;34m(e, name)\u001b[0m\n\u001b[0;32m   6860\u001b[0m   \u001b[0mmessage\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmessage\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;33m(\u001b[0m\u001b[1;34m\" name: \"\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0mname\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mname\u001b[0m \u001b[1;32mis\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[1;32mNone\u001b[0m \u001b[1;32melse\u001b[0m \u001b[1;34m\"\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   6861\u001b[0m   \u001b[1;31m# pylint: disable=protected-access\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 6862\u001b[1;33m   \u001b[0msix\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mraise_from\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcore\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_status_to_exception\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0me\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcode\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmessage\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   6863\u001b[0m   \u001b[1;31m# pylint: enable=protected-access\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   6864\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32md:\\2005\\.venv\\lib\\site-packages\\six.py\u001b[0m in \u001b[0;36mraise_from\u001b[1;34m(value, from_value)\u001b[0m\n",
      "\u001b[1;31mInvalidArgumentError\u001b[0m: indices[1] = [0,1] is out of order. Many sparse ops require sorted indices.\n    Use `tf.sparse.reorder` to create a correctly ordered copy.\n\n [Op:SparseToDense]"
     ]
    }
   ],
   "source": [
    "# 转化成稠密矩阵\n",
    "tf.sparse.to_dense(s2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:38:13.235002Z",
     "start_time": "2022-01-21T12:38:13.225027Z"
    }
   },
   "outputs": [],
   "source": [
    "# 可以通过reorder对稀疏tensor重新排序.\n",
    "s3 = tf.sparse.reorder(s2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:38:24.286824Z",
     "start_time": "2022-01-21T12:38:24.275852Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(3, 4), dtype=int32, numpy=\n",
       "array([[0, 2, 1, 0],\n",
       "       [0, 0, 0, 0],\n",
       "       [0, 0, 0, 3]])>"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.sparse.to_dense(s3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 变量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:42:38.089682Z",
     "start_time": "2022-01-21T12:42:38.013885Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Variable 'Variable:0' shape=(2, 3) dtype=int32, numpy=\n",
       "array([[1, 2, 3],\n",
       "       [4, 5, 6]])>"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 变量即内部的值可以变化. 比如神经网络中要学习的w,b就是变量. \n",
    "# tf.Variable来定义即可.\n",
    "v = tf.Variable([[1, 2, 3], [4, 5, 6]])\n",
    "v"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:42:50.382064Z",
     "start_time": "2022-01-21T12:42:50.373089Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2, 3],\n",
       "       [4, 5, 6]])"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 返回的是ndarray\n",
    "v.numpy()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:42:56.003158Z",
     "start_time": "2022-01-21T12:42:55.988199Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(2, 3), dtype=int32, numpy=\n",
       "array([[1, 2, 3],\n",
       "       [4, 5, 6]])>"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 返回的是变量的值创建的tensor\n",
    "v.value()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:44:27.972012Z",
     "start_time": "2022-01-21T12:44:27.941095Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Variable 'UnreadVariable' shape=(2, 3) dtype=int32, numpy=\n",
       "array([[ 2,  4,  6],\n",
       "       [ 8, 10, 12]])>"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v.assign(v * 2)  # v = v * 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:44:38.594909Z",
     "start_time": "2022-01-21T12:44:38.586929Z"
    },
    "collapsed": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Variable 'Variable:0' shape=(2, 3) dtype=int32, numpy=\n",
       "array([[ 2,  4,  6],\n",
       "       [ 8, 10, 12]])>"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:45:33.112908Z",
     "start_time": "2022-01-21T12:45:33.091965Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "'ResourceVariable' object does not support item assignment",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-34-8d05f3bcdc1c>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mv\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m44\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m: 'ResourceVariable' object does not support item assignment"
     ]
    }
   ],
   "source": [
    "v[0, 1] = 44"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:46:30.266779Z",
     "start_time": "2022-01-21T12:46:30.243840Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Variable 'UnreadVariable' shape=(2, 3) dtype=int32, numpy=\n",
       "array([[ 2, 44,  6],\n",
       "       [ 8, 10, 12]])>"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 变量的赋值必须通过assign方法\n",
    "v[0, 1].assign(44)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:46:57.715634Z",
     "start_time": "2022-01-21T12:46:57.708654Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Variable 'UnreadVariable' shape=(2, 3) dtype=int32, numpy=\n",
       "array([[ 2, 44,  6],\n",
       "       [ 7,  8,  9]])>"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v[1].assign([7, 8, 9])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 变量赋值不能用=, 必须用assign"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# tf2.0只有常量和变量. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### tensorflow数学运算"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 有两种方式: 一种直接用python的算术运算符即可. 另一种使用tensorflow封装的数学运算函数."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:50:57.410423Z",
     "start_time": "2022-01-21T12:50:57.406434Z"
    }
   },
   "outputs": [],
   "source": [
    "a = tf.constant(2)\n",
    "b = tf.constant(3)\n",
    "c = tf.constant(5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:51:06.845051Z",
     "start_time": "2022-01-21T12:51:06.731355Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(), dtype=int32, numpy=5>"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a + b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:51:17.477429Z",
     "start_time": "2022-01-21T12:51:17.451498Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(), dtype=int32, numpy=-1>"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a - b "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:52:36.369793Z",
     "start_time": "2022-01-21T12:52:36.243132Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(), dtype=float64, numpy=0.6666666666666666>"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# tensorflow内部的运算函数\n",
    "tf.add(a, b)\n",
    "tf.subtract(a, b)\n",
    "tf.multiply(a, b)\n",
    "tf.divide(a, b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:53:11.993130Z",
     "start_time": "2022-01-21T12:53:11.915828Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[7, 5, 8, 1],\n",
       "       [2, 1, 4, 4],\n",
       "       [5, 3, 6, 0]])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "n = np.random.randint(0, 10, size=(3, 4))\n",
    "n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:53:22.357197Z",
     "start_time": "2022-01-21T12:53:22.339245Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([14,  9, 18,  5])"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "n.sum(axis=0)\n",
    "# 按照列进行求和"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:54:10.399652Z",
     "start_time": "2022-01-21T12:54:10.363747Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(), dtype=int32, numpy=46>"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# tensorflow的聚合运算, 都会reduce\n",
    "# tensorflow中的聚合和numpy是一样, 不指定axis, 会把所有的维度聚掉. \n",
    "tf.reduce_sum(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:55:06.059383Z",
     "start_time": "2022-01-21T12:55:06.043425Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(4,), dtype=int32, numpy=array([14,  9, 18,  5])>"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.reduce_sum(n, axis=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:55:38.631784Z",
     "start_time": "2022-01-21T12:55:38.619816Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([21, 11, 14])"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.reduce_sum(n, axis=1).numpy()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:56:58.468544Z",
     "start_time": "2022-01-21T12:56:58.435632Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(3, 4), dtype=int32, numpy=\n",
       "array([[128, 156, 132, 154],\n",
       "       [111, 132,  98,  75],\n",
       "       [ 61,  73,  76,  96]])>"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 矩阵的乘法.\n",
    "x = np.random.randint(0, 10, size=(3, 5))\n",
    "y = np.random.randint(0, 10, size=(5, 4))\n",
    "# matrix multiply 矩阵乘法, 即点乘\n",
    "tf.matmul(x, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:57:23.627089Z",
     "start_time": "2022-01-21T12:57:23.612130Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 52,  36,  99,  71],\n",
       "       [ 60,  26,  90, 120],\n",
       "       [ 67,  79, 171, 143]])"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 矩阵乘法的简写\n",
    "x @ y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T13:00:05.855996Z",
     "start_time": "2022-01-21T13:00:05.789176Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 52,  36,  99,  71],\n",
       "       [ 60,  26,  90, 120],\n",
       "       [ 67,  79, 171, 143]])"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x.dot(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T12:59:41.386675Z",
     "start_time": "2022-01-21T12:59:41.373202Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(3, 4), dtype=int32, numpy=\n",
       "array([[ 52,  36,  99,  71],\n",
       "       [ 60,  26,  90, 120],\n",
       "       [ 67,  79, 171, 143]])>"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# @符号表示矩阵的点乘, 在tensorflow中和numpy中是通用.\n",
    "tf.constant(x) @ tf.constant(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 没有tf.dot\n",
    "tf.dot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T13:14:23.653718Z",
     "start_time": "2022-01-21T13:14:23.238303Z"
    },
    "collapsed": true
   },
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "\n",
       "        if (window._pyforest_update_imports_cell) { window._pyforest_update_imports_cell('import numpy as np'); }\n",
       "    "
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/javascript": [
       "\n",
       "        if (window._pyforest_update_imports_cell) { window._pyforest_update_imports_cell('import numpy as np'); }\n",
       "    "
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "ename": "InvalidArgumentError",
     "evalue": "Incompatible shapes: [3,5] vs. [5,4] [Op:Mul]",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mInvalidArgumentError\u001b[0m                      Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-63-cbf41ee0d004>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[0mx\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrandom\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrandint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m10\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0msize\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m3\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m5\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      2\u001b[0m \u001b[0my\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrandom\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrandint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m10\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0msize\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m5\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m4\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mtf\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmultiply\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;32md:\\2005\\.venv\\lib\\site-packages\\tensorflow\\python\\util\\dispatch.py\u001b[0m in \u001b[0;36mwrapper\u001b[1;34m(*args, **kwargs)\u001b[0m\n\u001b[0;32m    199\u001b[0m     \u001b[1;34m\"\"\"Call target, and fall back on dispatchers if there is a TypeError.\"\"\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    200\u001b[0m     \u001b[1;32mtry\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 201\u001b[1;33m       \u001b[1;32mreturn\u001b[0m \u001b[0mtarget\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    202\u001b[0m     \u001b[1;32mexcept\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mTypeError\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mValueError\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    203\u001b[0m       \u001b[1;31m# Note: convert_to_eager_tensor currently raises a ValueError, not a\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32md:\\2005\\.venv\\lib\\site-packages\\tensorflow\\python\\ops\\math_ops.py\u001b[0m in \u001b[0;36mmultiply\u001b[1;34m(x, y, name)\u001b[0m\n\u001b[0;32m    516\u001b[0m   \"\"\"\n\u001b[0;32m    517\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 518\u001b[1;33m   \u001b[1;32mreturn\u001b[0m \u001b[0mgen_math_ops\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmul\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mname\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    519\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    520\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32md:\\2005\\.venv\\lib\\site-packages\\tensorflow\\python\\ops\\gen_math_ops.py\u001b[0m in \u001b[0;36mmul\u001b[1;34m(x, y, name)\u001b[0m\n\u001b[0;32m   6065\u001b[0m       \u001b[1;32mreturn\u001b[0m \u001b[0m_result\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   6066\u001b[0m     \u001b[1;32mexcept\u001b[0m \u001b[0m_core\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_NotOkStatusException\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 6067\u001b[1;33m       \u001b[0m_ops\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mraise_from_not_ok_status\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0me\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mname\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   6068\u001b[0m     \u001b[1;32mexcept\u001b[0m \u001b[0m_core\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_FallbackException\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   6069\u001b[0m       \u001b[1;32mpass\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32md:\\2005\\.venv\\lib\\site-packages\\tensorflow\\python\\framework\\ops.py\u001b[0m in \u001b[0;36mraise_from_not_ok_status\u001b[1;34m(e, name)\u001b[0m\n\u001b[0;32m   6860\u001b[0m   \u001b[0mmessage\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmessage\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;33m(\u001b[0m\u001b[1;34m\" name: \"\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0mname\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mname\u001b[0m \u001b[1;32mis\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[1;32mNone\u001b[0m \u001b[1;32melse\u001b[0m \u001b[1;34m\"\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   6861\u001b[0m   \u001b[1;31m# pylint: disable=protected-access\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 6862\u001b[1;33m   \u001b[0msix\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mraise_from\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcore\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_status_to_exception\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0me\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcode\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmessage\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   6863\u001b[0m   \u001b[1;31m# pylint: enable=protected-access\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   6864\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32md:\\2005\\.venv\\lib\\site-packages\\six.py\u001b[0m in \u001b[0;36mraise_from\u001b[1;34m(value, from_value)\u001b[0m\n",
      "\u001b[1;31mInvalidArgumentError\u001b[0m: Incompatible shapes: [3,5] vs. [5,4] [Op:Mul]"
     ]
    }
   ],
   "source": [
    "x = np.random.randint(0, 10, size=(3, 5))\n",
    "y = np.random.randint(0, 10, size=(5, 4))\n",
    "# multiply是普通乘法, 矩阵和矩阵之间是对应位置的元素相乘. 这样的话就要求相乘的矩阵的shape必须一致.\n",
    "tf.multiply(x, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 使用TensorFlow实现线性回归"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "invalid syntax (94727567.py, line 2)",
     "output_type": "error",
     "traceback": [
      "\u001b[1;36m  File \u001b[1;32m\"C:\\Users\\ASUS\\AppData\\Local\\Temp\\ipykernel_2360\\94727567.py\"\u001b[1;36m, line \u001b[1;32m2\u001b[0m\n\u001b[1;33m    1. 找到算法的预测函数. y = wx + b\u001b[0m\n\u001b[1;37m       ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m invalid syntax\n"
     ]
    }
   ],
   "source": [
    "# 实现一个算法从以下三步入手:\n",
    "# 1. 找到算法的预测函数. y = wx + b\n",
    "# 2. 找到算法的损失函数. 最小二乘法  \n",
    "# 3. 使用梯度下降求损失最小的时候的参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T13:20:19.378211Z",
     "start_time": "2022-01-21T13:20:17.963430Z"
    }
   },
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T13:21:09.260856Z",
     "start_time": "2022-01-21T13:21:09.155632Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PathCollection at 0x178593e2640>"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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wCjCBwAAMIrwAQAAjCJ8AAAAowgfAADAKMIHAAAwivABAACMInwAAACjCB8AAMAowgcAADCK8AEAAIwifAAAAKMIHwAAwCjCBwAAMIrwAQAAjCJ8AAAAowgfAADAKMIHAAAwivABAACMInwAAACjCB8AAMAowgcAADCK8AEAAIwifAAAAKMIHwAAwCjCBwAAMIrwAQAAjCJ8AAAAowgfAADAKMIHAAAwivABAACMsj18nD59Wk8++aSi0aimTp2qK6+8Uk8//bRSqZTdpwIAAFnoG3b/wmeeeUYvvPCCtm7dqrlz5+rAgQN66KGHFAqFtHr1artPBwAAsozt4WPfvn268847tWLFCknSFVdcoZdfflkHDhyw+1QAACAL2X7bZfHixXrjjTd05MgRSdK7776rt99+W3fccce4xw8PDyuRSKS9AABA7rJ95mPdunWKx+OaM2eO/H6/ksmkNm7cqHvvvXfc4xsbG9XQ0GB3GQAAwKNsn/nYvn27WlpatG3bNnV2dmrr1q363e9+p61bt457/Pr16xWPx0dfvb29dpcEAAA8xGdZlmXnLywvL9cTTzyhurq60bFf//rXamlp0X/+85/z/nwikVAoFFI8HldRUZGdpQEAAIdkcv22febjyy+/VEFB+q/1+/1stQUAAJIcWPNRU1OjjRs3asaMGZo7d64OHTqkzZs36+GHH7b7VACAsyRTljp6BtQ/OKTSYEDV0WL5C3xulwWksf22y+DgoH7xi19ox44d6u/vV1lZme6991798pe/1JQpU87789x2AYDJaeuKqaG1W7H40OhYJBRQfU2FllVGXKwM+SCT67ft4eNiET4AIHNtXTGtaunU2f9BH5nzaKqtIoDAUa6u+QAAmJVMWWpo7R4TPCSNjjW0diuZ8tTfmshjhA8AMCiZsrTv6AntOnxc+46esCUQdPQMpN1qOZslKRYfUkfPwEWfC7CD7QtOAQDjc2pNRv/gxMFjMscBTmPmAwAMGFmTcfYMRV98SKtaOtXWFZv07y4NBmw9DnAa4QMAHOb0mozqaLEioYAm2lDr05kZlupo8aR+P2A3wgcAOMzpNRn+Ap/qayokaUwAGXlfX1NBvw94BuEDABxmYk3GssqImmqrFA6l31oJhwJss4XnsOAUABxmak3GssqIllSE6XAKzyN8AIDDRtZk9MWHxl334dOZGQo7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AMAowocBzz//vKLRqAKBgObNm6e33nrL7ZKyTmNjo66//noFg0GVlpbqrrvu0ocffuh2WTmhsbFRPp9Pa9ascbuUrHT8+HHV1taqpKRE06ZN07XXXquDBw+6XVbWOX36tJ588klFo1FNnTpVV155pZ5++mmlUim3S8sKe/bsUU1NjcrKyuTz+bRz5860zy3L0lNPPaWysjJNnTpVt9xyiz744AN3ihXhw3Hbt2/XmjVrtGHDBh06dEg33nijli9frmPHjrldWlbZvXu36urq9M4776i9vV2nT5/W0qVLdfLkSbdLy2r79+9Xc3Ozrr76ardLyUqff/65Fi1apG9+85t67bXX1N3drd///ve69NJL3S4t6zzzzDN64YUXtGXLFv373//Ws88+q9/+9rf6wx/+4HZpWeHkyZO65pprtGXLlnE/f/bZZ7V582Zt2bJF+/fvVzgc1pIlS0afp2acBUdVV1dbK1euTBubM2eO9cQTT7hUUW7o7++3JFm7d+92u5SsNTg4aM2ePdtqb2+3br75Zmv16tVul5R11q1bZy1evNjtMnLCihUrrIcffjht7O6777Zqa2tdqih7SbJ27Ngx+j6VSlnhcNj6zW9+Mzo2NDRkhUIh64UXXnChQsti5sNBp06d0sGDB7V06dK08aVLl2rv3r0uVZUb4vG4JKm4uNjlSrJXXV2dVqxYodtvv93tUrLWq6++qvnz5+uee+5RaWmprrvuOr344otul5WVFi9erDfeeENHjhyRJL377rt6++23dccdd7hcWfbr6elRX19f2rWosLBQN998s2vXIs89WC6XfPbZZ0omk5o+fXra+PTp09XX1+dSVdnPsiytXbtWixcvVmVlpdvlZKVXXnlFBw8e1IEDB9wuJat9/PHHampq0tq1a/Xzn/9cHR0deuyxx1RYWKgf/vCHbpeXVdatW6d4PK45c+bI7/crmUxq48aNuvfee90uLeuNXG/GuxZ98sknbpRE+DDB5/Olvbcsa8wYLtwjjzyi9957T2+//bbbpWSl3t5erV69Wq+//roCgYDb5WS1VCql+fPna9OmTZKk6667Th988IGampoIHxnavn27WlpatG3bNs2dO1eHDx/WmjVrVFZWpgcffNDt8nKCl65FhA8HXXbZZfL7/WNmOfr7+8ckUFyYRx99VK+++qr27Nmjyy+/3O1ystLBgwfV39+vefPmjY4lk0nt2bNHW7Zs0fDwsPx+v4sVZo9IJKKKioq0sauuukp//etfXaooe/30pz/VE088oR/84AeSpO985zv65JNP1NjYSPi4SOFwWNKZGZBIJDI67ua1iDUfDpoyZYrmzZun9vb2tPH29nYtXLjQpaqyk2VZeuSRR/S3v/1N//znPxWNRt0uKWvddtttev/993X48OHR1/z583X//ffr8OHDBI8MLFq0aMyW7yNHjmjmzJkuVZS9vvzySxUUpF+S/H4/W21tEI1GFQ6H065Fp06d0u7du127FjHz4bC1a9fqgQce0Pz587VgwQI1Nzfr2LFjWrlypdulZZW6ujpt27ZNu3btUjAYHJ1NCoVCmjp1qsvVZZdgMDhmrcwll1yikpIS1tBk6PHHH9fChQu1adMmfe9731NHR4eam5vV3NzsdmlZp6amRhs3btSMGTM0d+5cHTp0SJs3b9bDDz/sdmlZ4YsvvtBHH300+r6np0eHDx9WcXGxZsyYoTVr1mjTpk2aPXu2Zs+erU2bNmnatGm677773CnYlT02eeaPf/yjNXPmTGvKlClWVVUV20MnQdK4r5deesnt0nICW20nr7W11aqsrLQKCwutOXPmWM3NzW6XlJUSiYS1evVqa8aMGVYgELCuvPJKa8OGDdbw8LDbpWWFf/3rX+P+N/LBBx+0LOvMdtv6+norHA5bhYWF1k033WS9//77rtXrsyzLcif2AACAfMSaDwAAYBThAwAAGEX4AAAARhE+AACAUYQPAABgFOEDAAAYRfgAAABGET4AAIBRhA8AAGAU4QMAABhF+AAAAEYRPgAAgFH/BxD+NynkLX9+AAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 加噪声\n",
    "x = np.linspace(0, 10, 20) + np.random.randn(20)\n",
    "y = np.linspace(0, 10, 20) + np.random.randn(20)\n",
    "plt.scatter(x, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T13:22:11.747410Z",
     "start_time": "2022-01-21T13:22:11.739432Z"
    }
   },
   "outputs": [],
   "source": [
    "from sklearn.linear_model import LinearRegression"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T13:22:25.163566Z",
     "start_time": "2022-01-21T13:22:25.122170Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "LinearRegression()"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "linear = LinearRegression()\n",
    "linear.fit(x.reshape(-1, 1), y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T13:22:31.333759Z",
     "start_time": "2022-01-21T13:22:31.322789Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1.02865183])"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "linear.coef_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T13:22:37.135490Z",
     "start_time": "2022-01-21T13:22:37.130503Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-0.38284364614107513"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "linear.intercept_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T13:23:29.746242Z",
     "start_time": "2022-01-21T13:23:29.636533Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x1785d4240a0>]"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.scatter(x, y)\n",
    "x_test = np.linspace(0, 10, 20)\n",
    "y_test = linear.coef_[0] * x_test + linear.intercept_\n",
    "plt.plot(x_test, y_test, c='r')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T13:28:56.371740Z",
     "start_time": "2022-01-21T13:28:56.348801Z"
    }
   },
   "outputs": [],
   "source": [
    "# 把W, B定义为变量.\n",
    "W = tf.Variable(np.random.randn() * 0.02)\n",
    "B = tf.Variable(0.)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "<>:1: SyntaxWarning: 'tuple' object is not callable; perhaps you missed a comma?\n",
      "<>:1: SyntaxWarning: 'tuple' object is not callable; perhaps you missed a comma?\n",
      "C:\\Users\\ASUS\\AppData\\Local\\Temp\\ipykernel_2360\\2259734295.py:1: SyntaxWarning: 'tuple' object is not callable; perhaps you missed a comma?\n",
      "  (20, 4) (4, )\n"
     ]
    },
    {
     "ename": "TypeError",
     "evalue": "'tuple' object is not callable",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_2360\\2259734295.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;33m(\u001b[0m\u001b[1;36m20\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m4\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m(\u001b[0m\u001b[1;36m4\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m: 'tuple' object is not callable"
     ]
    }
   ],
   "source": [
    "(20, 4) (4, )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T13:30:20.014199Z",
     "start_time": "2022-01-21T13:30:20.003227Z"
    }
   },
   "outputs": [],
   "source": [
    "# 定义预测函数\n",
    "def linear_regression(x):\n",
    "    return W * x + B"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T13:42:30.139286Z",
     "start_time": "2022-01-21T13:42:30.131308Z"
    }
   },
   "outputs": [],
   "source": [
    "# 定义损失函数\n",
    "# 最小二乘法\n",
    "def mean_square_loss(y_pred, y_true):\n",
    "    return tf.reduce_mean(tf.square(y_pred - y_true))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T13:42:36.244119Z",
     "start_time": "2022-01-21T13:42:36.234147Z"
    }
   },
   "outputs": [],
   "source": [
    "# 优化器, 即梯度下降算法\n",
    "optimizer = tf.optimizers.SGD()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T13:42:36.413173Z",
     "start_time": "2022-01-21T13:42:36.402202Z"
    }
   },
   "outputs": [],
   "source": [
    "# 定义优化过程\n",
    "def run_optimization():\n",
    "    # 需要把计算过程放在梯度带(GradientTape)中执行, 可以实现自动微分.\n",
    "    with tf.GradientTape() as g:\n",
    "        pred = linear_regression(x)\n",
    "        loss = mean_square_loss(pred, y)\n",
    "        \n",
    "    # 计算梯度\n",
    "    gradients = g.gradient(loss, [W, B])\n",
    "    \n",
    "    # 更新W,B\n",
    "    optimizer.apply_gradients(zip(gradients, [W, B]))\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T13:42:50.485948Z",
     "start_time": "2022-01-21T13:42:36.627600Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "step:1, loss: 5.028132438659668, W: 0.7124658226966858, B:0.10037873685359955\n"
     ]
    },
    {
     "data": {
      "image/png": "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BQcHF5hfdPzPcw0YMEADBgxQdna2vv32WyUmJmrw4MFq3LixOnfurDPOOEPjxo3TuHHj9Ndff+mzzz7Tgw8+qN69e2vnzp1FrpzKDaJpaWmFfrZnz54C3386brvtNl166aV5x0X9OziZgIAAxcXF6amnnirRaqHSXFup6L+33LbjAztgN8IMUMEuvfRSPfbYY9q9e7euvfbaYs/Lvdkff6N74YUXyq22+++/X6+++qoee+wx3X777QoJCdGFF16odevWqXXr1qpSpUqx7+3Ro4eefPJJpaSkFBhqKukKGMlcm4SEBNWuXTsvJJ1MYGCgevTooRo1aujTTz/VunXr1Llz5wLn1KhRQ1dffbV2796tMWPGaNu2bYWGwyQz0TY4OFhJSUm65ppr8tp37dqlzz//vMwmvtavX1/169cv8flpaWlF9hblDjX+87MCAwOL7LUr7bVdunSpfvvtt7yetZycHM2bN09NmzZVgwYNSlw7UBEIM0AxPv/88yJ3hs0dXjlVXbt21W233aabbrpJq1evVvfu3VWtWjWlpaXp66+/VqtWrTRy5Ei1aNFCTZs21fjx42VZlmrVqqUFCxZoyZIlp/X9JxIQEKCEhARde+21euaZZzRx4kQ988wz6tatm84//3yNHDlSjRs3VmZmprZs2aIFCxbkrSAaM2aMXn75ZfXt21dTpkxRvXr19MYbb+jHH3+UVLLlumPGjNG7776r7t27a+zYsWrdurU8Ho927NihxYsX65577lGnTp00adIk7dq1SxdffLEaNGigv/76S88884wCAgLUo0cPSVJsbKxiYmLUoUMH1a1bV9u3b9fTTz+tRo0aFbshYI0aNfTwww/rwQcf1I033qhBgwZp//79io+PV1BQUN7KrYrWu3dvNWjQQLGxsWrRooU8Ho/Wr1+vadOmqXr16rr77rvzzm3VqpXmzp2refPmqUmTJgoKClKrVq1KfG1z1alTRxdddJEefvjhvNVMP/74Y4nCaUpKilJSUiSZ3pzDhw/rnXfekSRFR0cXGSSB02Lv/GPA++SucCnulZqaesLVTL///nuRn5e7YibXyy+/bHXq1MmqVq2aFRwcbDVt2tS68cYbrdWrV+edk5KSYvXs2dMKCQmxatasaV1zzTXWjh07LElWXFzcSb+7OLmrmd5+++0if96pUyerZs2aeauFUlNTreHD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\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "step:101, loss: 2.7527976036071777, W: 0.9836114048957825, B:-0.06909146904945374\n",
      "step:201, loss: 2.7368969917297363, W: 1.0013676881790161, B:-0.19278165698051453\n",
      "step:301, loss: 2.731062412261963, W: 1.0121238231658936, B:-0.2677096426486969\n",
      "step:401, loss: 2.7289211750030518, W: 1.0186396837234497, B:-0.3130986988544464\n",
      "step:501, loss: 2.728135585784912, W: 1.022586703300476, B:-0.3405940532684326\n",
      "step:601, loss: 2.7278473377227783, W: 1.0249778032302856, B:-0.3572499752044678\n",
      "step:701, loss: 2.727741241455078, W: 1.0264261960983276, B:-0.36733973026275635\n",
      "step:801, loss: 2.7277026176452637, W: 1.0273035764694214, B:-0.373451828956604\n",
      "step:901, loss: 2.7276883125305176, W: 1.0278351306915283, B:-0.3771543800830841\n",
      "step:1001, loss: 2.7276828289031982, W: 1.028157114982605, B:-0.37939730286598206\n",
      "step:1101, loss: 2.7276816368103027, W: 1.02835214138031, B:-0.3807559311389923\n",
      "step:1201, loss: 2.7276806831359863, W: 1.0284702777862549, B:-0.38157904148101807\n",
      "step:1301, loss: 2.727680206298828, W: 1.0285418033599854, B:-0.38207757472991943\n",
      "step:1401, loss: 2.727680206298828, W: 1.0285851955413818, B:-0.3823795020580292\n",
      "step:1501, loss: 2.727680206298828, W: 1.028611421585083, B:-0.382562518119812\n",
      "step:1601, loss: 2.727680206298828, W: 1.0286272764205933, B:-0.3826732337474823\n",
      "step:1701, loss: 2.727679967880249, W: 1.0286370515823364, B:-0.3827403485774994\n",
      "step:1801, loss: 2.727680206298828, W: 1.0286427736282349, B:-0.382781058549881\n",
      "step:1901, loss: 2.72767972946167, W: 1.0286463499069214, B:-0.38280561566352844\n",
      "step:2001, loss: 2.727679967880249, W: 1.0286484956741333, B:-0.3828204274177551\n",
      "step:2101, loss: 2.72767972946167, W: 1.0286498069763184, B:-0.382829487323761\n",
      "step:2201, loss: 2.727679967880249, W: 1.0286505222320557, B:-0.38283494114875793\n",
      "step:2301, loss: 2.7276804447174072, W: 1.0286509990692139, B:-0.3828379213809967\n",
      "step:2401, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:2501, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:2601, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:2701, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:2801, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:2901, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:3001, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:3101, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:3201, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:3301, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:3401, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:3501, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:3601, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:3701, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:3801, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:3901, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:4001, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:4101, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:4201, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:4301, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:4401, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:4501, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:4601, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:4701, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:4801, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n",
      "step:4901, loss: 2.727679967880249, W: 1.0286511182785034, B:-0.382839173078537\n"
     ]
    },
    {
     "data": {
      "image/png": "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DDPFxcVZgPXee+9lXhs1apQFWOPHj89y72OPPWb5+vpa6enplmVZ1saNGy3AmjBhQpb7Dh48aPn5+WXrMs+Qnp5unT171vr1118twPr000+zvXZeh4cyhpkWLlxonT171jp16pT1zTffWFdddZUVHh5u/fXXX5n3dujQwapSpUqW7n3Lsqz+/ftbvr6+1vHjxy3LsqynnnrKcrlc1p49e7Lc16FDBwuwVq9enXmtbdu2FmCtXLkyy73R0dFWiRIlsr33ixYtsgDriy++sCzLsl599VULsE6cOJHr7/HWW2+1GjVqdMH3IePPOi4uzrIsy/rrr78sPz8/q3PnzlnuO3DggOXj42N169Yt81qvXr0swPrwww+z3Nu5c2frqquuuuDr5teff/5pXXfddRZgAZa3t7fVqlUrKzo62kpKSspyb27DKnl9by3LsgDLz8/POnLkSOa11NRUq169elbt2rUvWu/SpUstb29v67vvvrMsK/dhzUaNGll169bNMix09uxZq2bNmhZgzZs3z7Isy/rmm28swJo/f3621xo3bpwFWIcPH86xFg0zSV6oZ0bkPLfddluWdsOGDUlOTubo0aMALF26FJfLRffu3UlNTc38CgkJ4ZprrskyHHP06FH69u1L1apVKVmyJN7e3lSvXh0g27AHmF6h/Ljvvvvw9vamdOnStG7dmsTERD7//HPKlSsHQHJyMitXruTOO++kdOnSWert3LkzycnJbNq0CYC1a9cSERFBeHh4ltfo2rVrjq9dvnx5brrppizXli5dSkREBI0aNcryWh06dMgyVNW8eXMA7r33Xj788EMOHTqU7flbtGjBrl27eOyxx/jqq69ITEy86PuxceNGTp8+zYMPPpjletWqVbnppptYuXJllusul4vIyMgs1xo2bMivv/56wddJT0/P8vtLS0u74P0VKlTg66+/ZsuWLbz00kvcfvvt/PjjjwwfPpwGDRpkG3bMSV7f2wzt2rUjODg4s+3l5cV9993Hvn37+O2333J9nYSEBPr06cPQoUOJiIi4YE2PP/44P/74I/379+fQoUMcPHiQvn37Zr5/5w8XuVyuXJ/rQt8TuRiFGZHzVKhQIUs7o8v89OnTgJmPYlkWwcHBeHt7Z/natGlT5gdTeno67du35+OPP+bpp59m5cqVxMbGZoaHjOc7V35X5bz88sts2bKFtWvX8uyzz/L7779zxx13ZM75OHbsGKmpqbzxxhvZau3cuTNAZr3Hjh3L8uGXIadrudX6+++/8+2332Z7LX9/fyzLynytNm3asGTJElJTU+nZsydVqlQhIiKC+fPnZz7X8OHDefXVV9m0aROdOnWiQoUKtGvX7oJLz48dO5ZrbZUrV878fobSpUtnW6nj4+Nz0SGPMWPGZPn95XV+U7NmzRg6dCgfffQRhw8fZvDgwezfv5/x48df9LF5fW8zhISEZHuOjGvnvw/nevbZZ/H29qZ///6cOHGCEydOcPLkScAMdZ04cSJzSKt379689NJLzJkzhypVqlCtWjX27t3Lk08+CcCVV14J/PP/VE6ve/z4cVwuV2YAF7kU2WejicgFVaxYEZfLxddff33B+QK7d+9m165dzJo1i169emV+f9++fbk+d35/Oq1Zs2bmpN82bdrg5+fHiBEjeOONN3jyyScpX748Xl5e9OjRg6ioqByfIywsDDAfOOdPHAY4cuRInmutWLEifn5+zJw5M8fHVKxYMfPXt99+O7fffjspKSls2rSJ6OhounXrRo0aNWjZsiUlS5ZkyJAhDBkyhBMnTvDf//6XZ555hg4dOnDw4MEsk04zZHxoZkw8Pdfhw4ezvP7lePTRR7n11lsz2zn9PbgYb29vRo0axaRJk9i9e/dF78/Pews5/7llXDs/sJ9r9+7d7N+/P8cwlPH3+K+//soMH0OHDmXQoEH89NNP+Pv7U716dfr06UOZMmVo2rQpALVq1cLPzy9zDs25vvvuO2rXrp3r8m+RvFCYEcmnW2+9lZdeeolDhw5x77335npfxof9+R90b731VqHV9vTTTzNr1ixeeukl+vTpg7+/PzfeeCM7duygYcOGlCpVKtfHtm3blldffZW9e/dmGWrKzwqYW2+9lXHjxlGhQoXMkHQxPj4+tG3blnLlyvHVV1+xY8cOWrZsmeWecuXKcffdd3Po0CEGDRrE/v37sw2HgZlo6+fnx9y5c7nnnnsyr//222+sWrWKu+++O8+/lwupXLkylStXzvP98fHxOfYWZQw1nvtcPj4+Ofba5fe9XblyJb///ntmz1paWhoLFy6kVq1aVKlSJdfHTZ48Odsk6507dzJ48GCef/552rZtS9myZbN838fHJ3NI6sCBAyxcuJD//Oc/+Pn5AVCyZEkiIyP5+OOPGT9+PP7+/pn3rl69OtsEe5H8UpgRj7Vq1aocd4bNGF65VK1bt+bRRx/loYceYuvWrbRp04YyZcoQHx/P+vXradCgAf369aNevXrUqlWLYcOGYVkWQUFBxMTEsGLFist6/Qvx9vZm3Lhx3Hvvvbz22muMGDGC1157jeuuu47rr7+efv36UaNGDZKSkti3bx8xMTGsWrUKgEGDBjFz5kw6derEmDFjCA4OZt68eXz//fdA3pbLDho0iMWLF9OmTRsGDx5Mw4YNSU9P58CBAyxfvpwnnniCa6+9lpEjR/Lbb7/Rrl07qlSpwokTJ3jttdfw9vambdu2AERGRhIREUGzZs244oor+PXXX5k8eTLVq1enTp06Ob5+uXLleO6553jmmWfo2bMnXbt25dixY4wePRpfX19GjRpVQO90/nTo0IEqVaoQGRlJvXr1SE9PZ+fOnUyYMIGyZcsycODAzHsbNGjAggULWLhwITVr1sTX15cGDRrk+b3NULFiRW666Saee+45ypQpw9SpU/n+++8vGk4bNWqU6/fq16+fZTfe3bt3s3jxYpo1a4aPjw+7du3ipZdeok6dOrzwwgtZHjt69GiaN2/OrbfeyrBhw0hOTmbkyJFUrFgx2y7IW7duzfx/NzExEcuyMldhNW/ePHPemUgmO2cfixSGjBUuuX3FxcVdcDXTH3/8kePzZayYyTBz5kzr2muvtcqUKWP5+flZtWrVsnr27Glt3bo18569e/dat9xyi+Xv72+VL1/euueee6wDBw5YgDVq1KiLvnZucltdkuHaa6+1ypcvn7laKC4uzurdu7d15ZVXWt7e3tYVV1xhtWrVynrxxRezPG737t3WzTffbPn6+lpBQUHWww8/nLlh2q5duzLva9u2rVW/fv0cX/vkyZPWiBEjrKuuusoqVaqUFRgYaDVo0MAaPHhw5uqapUuXWp06dbKuvPJKq1SpUlalSpWszp07W19//XXm80yYMMFq1aqVVbFiRatUqVJWtWrVrIcfftjav39/5j25/dm88847VsOGDTNf//bbb8+2SqtXr15WmTJlstWf8WdRkBYuXGh169bNqlOnjlW2bFnL29vbqlatmtWjRw9r7969We7dv3+/1b59e8vf398CrOrVq2d+Ly/vrWWZ1UxRUVHW1KlTrVq1alne3t5WvXr1rA8++OCS6s/t79sPP/xgtWnTxgoKCrJKlSpl1a5d2xoxYoR18uTJHJ9n69atVrt27azSpUtbAQEB1h133GHt27cv230ZK81y+jr3/1mRDC7LOm9zAhGRczz66KPMnz+fY8eOXXCYStyHy+UiKiqKKVOm2F2KSJHQMJOIZBozZgyVK1emZs2anDx5kqVLl/LOO+8wYsQIBRkRcVsKMyKSydvbm1deeYXffvuN1NRU6tSpw8SJE7PM6RARcTcaZhIRERFH06Z5IiIi4mgKMyIiIuJoCjMiIiLiaB4/ATg9PZ3Dhw/j7++vg8xEREQcwrIskpKSqFy58kU37fT4MHP48GGqVq1qdxkiIiJyCQ4ePHjBIzigGISZjDNADh48SEBAgM3ViIiISF4kJiZStWrVzM/xC/H4MJMxtBQQEKAwIyIi4jB5mSKiCcAiIiLiaAozIiIi4mgKMyIiIuJoCjMiIiLiaAozIiIi4mgKMyIiIuJoCjMiIiLiaAozIiIi4mgKMyIiIuJoHr8DsIiISHGTlm4RG3eco0nJVPL3pUVYEF4lPPewZYUZERERD7JsdzyjY/YSn5CceS000JdRkeF0jAi1sbLCo2EmERERD7Fsdzz95m7PEmQAjiQk02/udpbtjrepssKlMCMiIuIB0tItRsfsxcrhexnXRsfsJS09pzucTWFGRETEA8TGHc/WI3MuC4hPSCY27njRFVVEFGZEREQ8wNGk3IPMpdznJAozIiIiHqCSv2+B3uckCjMiIiIeoEVYEKGBvuS2ANuFWdXUIiyoKMsqEgozIiIiHsCrhItRkeEA2QJNRntUZLhH7jejMCMiIuIhOkaEMq17E0ICsw4lhQT6Mq17E4/dZ0ab5omIiHiQjhGh3BIeoh2ARURExLm8SrhoWauC3WUUGQ0ziYiIiKMpzIiIiIijKcyIiIiIoynMiIiIiKMpzIiIiIijKcyIiIiIoynMiIiIiKMpzIiIiIijadM8ERGRC0hLt4rVbrpOpDAjIiKSi2W74xkds5f4hOTMa6GBvoyKDPfYc46cSMNMIiIiOVi2O55+c7dnCTIARxKS6Td3O8t2x9tUmZxPYUZEROQ8aekWo2P2YuXwvYxro2P2kpae0x1S1BRmREREzhMbdzxbj8y5LCA+IZnYuONFV5TkSmFGRETkPEeTcg8yl3KfFC6FGRERkfNU8vct0PukcCnMiIiInKdFWBChgb7ktgDbhVnV1CIsqCjLklwozIiIiJzHq4SLUZHhANkCTUZ7VGS49ptxEwozIiIiOegYEcq07k0ICcw6lBQS6Mu07k2K/T4zaekWG38+xqc7D7Hx52O2ruzSpnkiIiK56BgRyi3hIdoB+Dzutpmgy7Isj14kn5iYSGBgIAkJCQQEBNhdjoiIiKNlbCZ4fnjIiHcF1WuVn89vDTOJiIhInrjrZoK2hpl169YRGRlJ5cqVcblcLFmyJMv3Lcvi+eefp3Llyvj5+XHDDTewZ88ee4oVEREp5tx1M0Fbw8zff//NNddcw5QpU3L8/vjx45k4cSJTpkxhy5YthISEcMstt5CUlFTElYqIiIi7biZo6wTgTp060alTpxy/Z1kWkydP5tlnn+Wuu+4CYPbs2QQHBzNv3jz69OlTlKWKiIgUe+66maDbzpmJi4vjyJEjtG/fPvOaj48Pbdu2ZcOGDTZWJiIiUjy562aCbhtmjhw5AkBwcHCW68HBwZnfy0lKSgqJiYlZvkREROTyuetmgm4bZjK4XFnfEMuysl07V3R0NIGBgZlfVatWLewSRUREiofUVLfcTNBtN80LCQkBTA9NaOg/b8zRo0ez9daca/jw4QwZMiSznZiYqEAjIiJyuZYvhz59ICaGjhERbrWZoNv2zISFhRESEsKKFSsyr505c4a1a9fSqlWrXB/n4+NDQEBAli8RERG5RGfOwJNPQocOsH8/vPgiYIacWtaqwO2NrqRlrQq27opsa8/MyZMn2bdvX2Y7Li6OnTt3EhQURLVq1Rg0aBDjxo2jTp061KlTh3HjxlG6dGm6detmY9UiIiLFxI8/QteusH27aUdFwSuv2FtTDmwNM1u3buXGG2/MbGcMD/Xq1YtZs2bx9NNPc/r0aR577DH++usvrr32WpYvX46/v79dJYuIiHg+y4LZs6F/f/j7b6hQAWbOhNtus7uyHOlsJhEREflHQgL07QsLFpj2jTfCnDlw5ZVFWkZ+Pr/ddgKwiIh4rrR0y20mj8o5Nm6Ebt3M3BgvL3jhBXj6afNrN6YwIyIiRWrZ7nhGx+zNcsZPaKAvoyLDbVnWK0BaGkRHw/PPm1+HhcH8+XDttXZXliduu5pJREQ8z7Ld8fSbuz3bYYVHEpLpN3c7y3bH21RZMfbbb9CuHTz3nAkyDzwAO3c6JsiAwoyIiBSRtHSL0TF7yWmiZsa10TF7SUv36Kmc7uWTT6BhQ1i7FsqWhfffh7lzwWFzTBVmRESkSMTGHc/WI3MuC4hPSCY27njRFVVcnToF/frBXXfBX39Bs2awYwf06GF3ZZdEYUZERIrE0aTcg8yl3CeX6LvvoHlzmD7dtJ9+Gr75BmrXtreuy6AJwCIiUiQq+fte/KZ83Cf5ZFnw5ptmN9+UFAgJMcNKt9xid2WXTT0zIiJSJFqEBREa6JvttOUMLsyqphZhQUVZVvHw559w++3w+OMmyHTpAt9+6xFBBhRmRESkiHiVcDEqMhwgW6DJaI+KDNd+MwVt1Sq45hqIiYFSpeC118yvr7jC7soKjMKMiIgUmY4RoUzr3oSQwKxDSSGBvkzr3kT7zBSks2dh+HC4+WY4fBjq1YPYWBgwAFyeFRg1Z0ZERIpUx4hQbgkP0Q7Ahennn81OvrGxpv3oozBpEpQubW9dhURhRkREipxXCRcta1WwuwzP9MEHZtl1UhKUKwfvvAP//rfdVRUqhRkRERFPkJQEUVHmUEiA6683G+BVq2ZvXUVAc2ZEREScbssWaNzYBJkSJWD0aFi9ulgEGVDPjIiIiHOlp8Mrr8CIEZCaasLLvHnQurXdlRUphRkREREnOnwYevaElStN+9574a23zDyZYkbDTCIiIk6zdKnZO2blSrNC6d13YcGCYhlkQD0zIiIizpGcbM5SeuMN027UyISYq66ytSy7qWdGRETECfbuhWuv/SfIDB4MmzYV+yAD6pkRERFxb5YFb78NgwbB6dPmGILZs6FTJ7srcxsKMyIiIu7q+HH4z3/g449Nu317E2RCQuyty81omElERMQdrVtnJvl+/DF4e8Orr8KXXyrI5EA9MyIiIu4kNRXGjIGxY80+MnXqwPz50LSp3ZW5LYUZERERd7F/PzzwAGzYYNoPPQSvvw5ly9palrvTMJOIiIg7+PBDs9R6wwYICDC9MTNnKsjkgXpmRERE7PT33zBggAkuAC1bmpOvw8LsrctB1DMjIiJil+3boUkTE2RcLnPG0rp1CjL5pJ4ZERGRopaeDq+9BsOGwZkzUKUKzJ0LbdvaXZkjKcyIiIgUpd9/hwcfhGXLTPuOO+Cdd6BCBTurcjQNM4mIiBSVr76Chg1NkPH1hWnTzD4yCjKXRWFGRESksKWkwBNPQMeOcPQoNGgAW7dC375mroxcFg0ziYiIFKYff4T774cdO0y7f38YPx78/Oyty4MozIiIiBQGy4JZs+Dxx83y6woVzKql226zuzKPozAjIiJS0E6cMENICxea9k03wfvvw5VX2lqWp9KcGRERkYK0YYPZyXfhQihZEqKjYflyBZlCpJ4ZERGRgpCWBuPGwejR5tc1a5ojCVq0sLsyj6cwIyIicrkOHoQePWDtWtPu3h3efNOcsSSFTsNMIiIil+OTT+Caa0yQKVvWzI2ZM0dBpgipZ0ZERORSnDoFQ4bAW2+ZdvPmMG8e1K5tb13FkHpmRERE8uvbb014eests+nd0KGwfr2CjE3UMyMiIpJXlgVTpsBTT5ldfUNCzJDSzTfbXVmxpjAjIiKSF3/8Ab17w9Klpt2lC7z3Hlxxhb11iYaZRERELmrlSjPJd+lS8PGB11+HmBgFGTehMCMiIpKbs2dh+HC45RaIj4err4bYWHNEgQ6IdBsaZhIREcnJzz9Dt24mvAA8+ihMmgSlS9tbl2SjnhkREZHzzZ0LjRubIFO+PCxebFYuKci4JfXMiIiIZEhMhKgoE2YA2rQxv65a1d665ILUMyMiIgKmF6ZxYxNevLxgzBhYtUpBxgHcOsykpqYyYsQIwsLC8PPzo2bNmowZM4b09HS7SxMREU+Rng4vvQStW8Mvv0D16rBuHTz3nAk14vbcepjp5ZdfZvr06cyePZv69euzdetWHnroIQIDAxk4cKDd5YmIiNMdPgw9e5ql1wD33QfTp0O5craWJfnj1mFm48aN3H777XTp0gWAGjVqMH/+fLZu3WpzZSIi4ngxMfDQQ3DsmJnY+8Ybpq0l147j1sNM1113HStXruTHH38EYNeuXaxfv57OnTvn+piUlBQSExOzfImIiGRKTjb7xNx2mwkyjRvD9u1md18FGUdy656ZoUOHkpCQQL169fDy8iItLY2xY8fStWvXXB8THR3N6NGji7BKERFxjL174f774bvvTHvwYIiONrv6imO5dc/MwoULmTt3LvPmzWP79u3Mnj2bV199ldmzZ+f6mOHDh5OQkJD5dfDgwSKsWERE3JJlmbkwTZuaIFOpEnz5JUycqCDjAVyWZVl2F5GbqlWrMmzYMKKiojKvvfjii8ydO5fvv/8+T8+RmJhIYGAgCQkJBAQEFFapIiLiro4fh0cegU8+Me0OHWD2bAgOtrcuuaD8fH67dc/MqVOnKFEia4leXl5ami0iInmzdq05IPKTT8DbGyZMgC++UJDxMG49ZyYyMpKxY8dSrVo16tevz44dO5g4cSK9e/e2uzQREXFnqalm07uxY80+MnXrwvz50KSJ3ZVJIXDrYaakpCSee+45PvnkE44ePUrlypXp2rUrI0eOpFSpUnl6Dg0ziYhcmrR0i9i44xxNSqaSvy8twoLwKuGA1T7798MDD8CGDab90EPw+utQtqytZUn+5Ofz263DTEFQmBERyb9lu+MZHbOX+ITkzGuhgb6MigynY0SojZVdxMKF0KcPJCRAQADMmGE2whPH8Zg5MyIiUvSW7Y6n39ztWYIMwJGEZPrN3c6y3fE2VXYBJ0+afWLuv98EmZYtYdcuBZliQmFGRMSh0tItNv58jE93HmLjz8dIS7/8jva0dIvRMXvJ6Zkyro2O2Vsgr1Vgtm83S67few9KlIARI8zZSjVq2F2ZFBG3ngAsIiI5K6xhoNi449l6ZM5lAfEJycTGHadlrQqX/DoFIj0dJk+GYcPg7FmoUsWceN22rb11SZFTz4yIiMMU5jDQ0aTcg8yl3Fdofv8dOneGJ54wQebOO82wkoJMsaQwIyLiIIU9DFTJ37dA7ysUy5ZBw4bw1Vfg62t29l28GIKC7KtJbKUwIyLiIPkZBroULcKCCA30JbcF2C7McFaLMBuCQ0oKDBkCnTrB0aPQoAFs3WpWL+mAyGJNYUZExEEKexjIq4SLUZHhANkCTUZ7VGR40e8388MPZoXSpEmm3b8/xMZC/fpFW4e4JYUZEREHKYphoI4RoUzr3oSQwKzPERLoy7TuTYp2nxnLgpkzzc69O3ZAhQrw2WfwxhtmiEkErWYSEXGUjGGgIwnJOc6bcWFCx+UOA3WMCOWW8BB7dwA+ccIMIX34oWm3awfvvw+VKxddDXnk2N2SPYTCjIiIg2QMA/Wbux0XZAk0BT0M5FXCZd/y6w0boFs3+PVXKFkSXnwRnnrK7CPjZhy7W7IHcb+/FSIickFuNQxU0NLS4IUXoE0bE2Rq1oRvvoGhQ902yDhut2QPpJ4ZEREHcothoIJ28CB072527wXz6zffNGcsuaGLLZN3YZbJ3xIe4uw/FwdQmBERcShbh4EK2scfwyOPwF9/mdOtp06FHj3sruqCHLVbsodTmBEREfucOgWDB5vTrQGaN4d586B2bXvrygPH7JZcDLjfAKSIiBQPu3ZBs2YmyLhcZl7M+vWOCDLgkN2SiwmFGRERKVqWZfaJufZa+N//IDQUVqyAl16CUqXsri7P3Hq35GJGYUZERIrOH3/AbbfBgAHmeIIuXUwPTbt2dleWb267W3IxpDAjIiJFY+VKuOYaWLoUfHzg9dchJgauuMLuyi6ZRy+TdxBNABYRkcJ19iw89xyMH2+GmK6+GhYsMCdfewCPXCbvMAozIiJSeH7+Gbp2hS1bTPvRR81hkaVL21tXAfOoZfIOpGEmEREpHHPmQKNGJsiULw+LF8Nbb3lckBH7qWdGREQKVmIiPPYYfPCBabdpA3PnQtWq9tYlHks9MyIiUnA2b4bGjU2Q8fKCMWNg1SoFGSlU6pkREZHLl55uJvg+9xykpkL16mYn31at7K5MigGFGRERuTyHD5tzlFatMu377oPp06FcOVvLkuJDw0wiInLpYmLMEutVq8zE3nffhfnzFWSkSKlnRkRE8u/0aXjqKXjzTdNu3NiEmKuusrcuKZbUMyMiIvmzZw+0aPFPkBk8GDZuVJAR26hnRkRE8sayzD4xgwdDcjJUqgSzZ0PHjnZXJsWcwoyIiFzc8ePw8MOwZIlpd+hggkxwsK1liYCGmURE5GLWrjUHRC5ZAt7eMGECfPGFgoy4DYUZERHJWWqq2Tfmxhvht9+gbl3YtAmGDIES+vgQ96FhJhERyW7/fujWzUzsBXjoIXj9dShb1tayRHKiaC0iIlktWGCGlTZuhIAA0545U0FG3JZ6ZkRExDh5Eh5/HGbNMu2WLc2RBDVq2FmVyEWpZ0ZERGD7dmjSxAQZl8vMlVm3TkFGHEE9MyIixVl6OkyaBMOHw9mzUKUKzJ0LbdvaXZlIninMiIgUV0eOQK9esHy5ad95J7zzDgQF2VuXSD4pzIiIFLK0dIvYuOMcTUqmkr8vLcKC8CrhsreoL7+EBx+Eo0fB1xcmT4ZHHzVDTCIOozAjIlKIlu2OZ3TMXuITkjOvhQb6MioynI4RoUVfUEoKDBtmwgtAgwbmgMj69Yu+FpECognAIiKFZNnuePrN3Z4lyAAcSUim39ztLNsdX7QF/fAD/Otf/wSZ/v0hNlZBRhxPYUZEpBCkpVuMjtmLlcP3Mq6NjtlLWnpOdxQwy4J33zWrlXbuhAoV4LPP4I03zBCTiMMpzIiIFILYuOPZemTOZQHxCcnExh0v3EJOnID774dHHoFTp+Cmm2DXLoiMLNzXFSlCCjMiIoXgaFLuQeZS7rsk33wDjRrBhx9CyZIQHW1WLl15ZeG9pogNNAFYRKQQVPLP2/BNXu/Ll7Q0GDsWRo82+8jUrGkm+bZoUfCvJeIG1DMjIlIIWoQFERroS24LnV2YVU0twgp4T5cDB8wp16NGmSDTvTvs2KEgIx5NYUZEpBB4lXAxKjIcIFugyWiPigwv2P1mFi82B0R+/bU5FPL992HOHHNYpIgHc/swc+jQIbp3706FChUoXbo0jRo1Ytu2bXaXJSJyUR0jQpnWvQkhgVmHkkICfZnWvUnB7TNz6hT06QN3320m/DZvbnpjevQomOcXcXNuPWfmr7/+onXr1tx44418+eWXVKpUiZ9//ply5crZXZqISJ50jAjllvCQwtsBeNcu6NoV/vc/0376aXjhBShVqmCeX8QB3DrMvPzyy1StWpX33nsv81oNneAqIg7jVcJFy1oVCvZJLcvsE/PUU3DmDISEmCGlm28u2NcRcQC3Hmb67LPPaNasGffccw+VKlWicePGvP322xd8TEpKComJiVm+REQ8yh9/mH1iBg40QaZLF/j2WwUZKbbcOsz88ssvTJs2jTp16vDVV1/Rt29fBgwYwPvvv5/rY6KjowkMDMz8qlq1ahFWLCJSyP77X2jYED7/HHx84PXXISYGrrjC7spEbOOyLKsI9tK+NKVKlaJZs2Zs2LAh89qAAQPYsmULGzduzPExKSkppKSkZLYTExOpWrUqCQkJBGhGv4g41Zkz8Nxz8MorZojp6qthwQITbEQ8UGJiIoGBgXn6/HbrOTOhoaGEh4dnuXb11VezePHiXB/j4+ODj49PYZcmIlJ09u0zk3y3bjXtRx+FSZOgdGl76xJxE249zNS6dWt++OGHLNd+/PFHqlevblNFIiJFbM4caNzYBJny5c1eMm+9pSAjcg63DjODBw9m06ZNjBs3jn379jFv3jxmzJhBVFSU3aWJiBSuxESze2/PnnDyJLRpY5Zh33WX3ZWJuB23DjPNmzfnk08+Yf78+URERPDCCy8wefJkHnjgAbtLExEpPJs3m96YDz6AEiVgzBhYtQq0oEEkR249Abgg5GcCkYiIrdLSYPx4GDkSUlOhWjWYNw9at7a7MpEi5zETgEVEio1Dh8zxA6tXm/a995q5MdrxXOSi3HqYSUSkWPjsM3NA5OrVZmLvu++aZdcKMiJ5op4ZERG7nD5tjiN4803TbtTIhJirrrK1LBGnUc+MiIgd9uyBFi3+CTKDB8OmTQoyIpdAPTMiIkXJsmD6dBgyBJKToVIlmD0bOna0uzIRx1KYEREpKseOwSOPwJIlpt2hgwkywcG2liXidBpmEhEpCmvWmEm+S5aAtze8+ip88YWCjEgBUM+MiEhhOnsWRo+GcePMEFPdujB/PjRpYndlIh5DYUZEpLDExUG3bmZiL8BDD8Hrr0PZsvbWJeJh8j3M9OCDD7Ju3brCqEVExHPMn2+WWm/aBAEBZsn1zJkKMiKFIN9hJikpifbt21OnTh3GjRvHoUOHCqMuERFnOnnS9MB062YOi2zZEnbuhPvus7syEY+V7zCzePFiDh06RP/+/fnoo4+oUaMGnTp1YtGiRZw9e7YwahQRcYbt281cmFmzwOWCESNg3ToIC7O7MhGPdkmrmSpUqMDAgQPZsWMHsbGx1K5dmx49elC5cmUGDx7MTz/9VNB1ioi4r/R0mDAB/vUv+OknqFLFHE3wwgtQUlMTRQrbZS3Njo+PZ/ny5SxfvhwvLy86d+7Mnj17CA8PZ9KkSQVVo4iI+zpyBDp1giefNCuX7rwTdu2Ctm3trkyk2Mh3mDl79iyLFy/m1ltvpXr16nz00UcMHjyY+Ph4Zs+ezfLly5kzZw5jxowpjHpFRNzHl1+avWOWLwdfX7Oz7+LFEBRkd2UixUq++z9DQ0NJT0+na9euxMbG0qhRo2z3dOjQgXI67VVEPFVKCgwbBpMnm3aDBmb1Uv36tpblNGnpFrFxxzmalEwlf19ahAXhVcJld1niQPkOM5MmTeKee+7B19c313vKly9PXFzcZRUmIuKWfvgB7r/frFAC6N8fXnnF9MxIni3bHc/omL3EJyRnXgsN9GVUZDgdI0JtrEycyGVZlmV3EYUpMTGRwMBAEhISCAgIsLscEXEqyzL7xAwYAKdOQYUK8N57EBlpd2WOs2x3PP3mbuf8D5+MPplp3Zso0Ei+Pr91NpOIyMWcOGF6Yx55xASZdu3g228VZC5BWrrF6Ji92YIMkHltdMxe0tI9+udsKWAKMyIiF/LNN2Yn3w8/NMusX3rJTPitXNnuyhwpNu54lqGl81lAfEIysXHHi64ocTxtgCAikpO0NHM45PPPm31katY0k3xbtLC7Mkc7mpR7kLmU+0RAYUZEJLsDB6B7d/j6a9Pu3h3efNOcsSSXpZJ/3iZK5/U+EdAwk4hIVosXm71jvv7aHAr5/vswZ46CTAFpERZEaKAvuS3AdmFWNbUI0149kncKMyIiYCb29ukDd99tJvw2bw47dkCPHnZX5lG8SrgYFRkOkC3QZLRHRYZrvxnJF4UZEZFdu6BZM5gxwxwQOXQorF8PtWvbXZlH6hgRyrTuTQgJzDqUFBLoq2XZckk0Z0ZEii/LgilT4KmnzK6+oaFmSKldO7sr83gdI0K5JTxEOwBLgVCYEZHi6Y8/oHdvWLrUtG+91WyKd8UV9tblcPk5osCrhIuWtSoUcYXiiRRmRKT4+e9/oWdPiI8HHx949VWIijJDTHLJdESB2EVzZkSk+DhzxsyHad/eBJmrr4bYWHO+koLMZck4ouD8DfGOJCTTb+52lu2Ot6kyKQ4UZkSkeNi3D1q3hvHjzVyZPn1g61Zo2NDuyhxPRxSI3RRmRMTzzZkDjRub8FK+vNlLZvp0KF3a7so8go4oELtpzoyIeK7ERHjsMfjgA9Nu0wbmzoWqVe2ty8PoiAKxm3pmRMQzbd5semM++AC8vOCFF2DVKgWZQqAjCsRu6pkREc+SlmbmxYwcCampUL06zJsHrVqZZcM/H9O+JgUs44iCIwnJOc6bcWE2xNMRBVJYFGZExHMcOmSOH1i92rTvu8/MjSlXTsuGC1HGEQX95m7HBVkCjY4okKKgYSZxpLR0i40/H+PTnYfY+PMxrZIQiIkxB0SuXm0m9r77LsyfnxlktGy4cOmIArGTembEcfQTtmRx+rQ5juDNN027cWMTYq66Crj4smEXZtnwLeEh6jm4TDqiQOyinhlxFP2ELVns2QMtWvwTZIYMgY0bM4MMaNlwUcs4ouD2RlfSslYFBRkpEgoz4hjamEsyWZaZC9OsGezeDZUqwZdfwoQJ5niCc2jZsIjnU5gRx9BP2ALAsWNw113Qrx8kJ0PHjvDtt+a/OdCyYRHPpzAjjqGfsIU1a8wk3yVLwNsbJk6Ezz+H4OBcH5KxbDi3wQ4XZs6Vlg2LOJfCjDiGfsIuxs6ehREj4KabzPLrunVh0yYYPBhKXPifsYxlw0C2QKNlwyKeQWFGHEM/YRdTcXHmGIKxY81cmd69Yds2aNIkz0+hZcMink1Ls8UxtDFXMTR/PvTta85YCgiAGTPMRniXQMuGRTyXy7Isj176kZiYSGBgIAkJCQQEBNhdjhQA7TNTDJw8CY8/DrNmmXbLluZIgho17KxKRIpQfj6/1TMjjqOfsD3ctm3QtSv89JOZD/Pss+acpZL650pEcqZ/HcSRMjbmEg+Sng6TJsHw4WbCb5Uq5sTrNm3srkxE3JzCjIjY78gR6NULli837bvugrffhiBN5haRi3PUaqbo6GhcLheDBg2yuxQRKShffmn2jlm+HPz8zM6+ixYpyIhInjmmZ2bLli3MmDGDhg0b2l2KiBSElBQYNgwmTzbtBg1gwQIID7e1LBFxHkf0zJw8eZIHHniAt99+m/Lly9tdjohcru+/h3/9658g8/jjEBurICMil8QRYSYqKoouXbpw8803X/TelJQUEhMTs3yJiJuwLHj3XWjaFHbuhIoVISYGXn8dfLVzs4hcGrcfZlqwYAHbtm1j69atebo/Ojqa0aNHF3JVIpJvJ05Anz7w4Yem3a4dvP8+VK5sa1ki4nxu3TNz8OBBBg4cyAcffIBvHn9qGz58OAkJCZlfBw8eLOQqReSivvnGTPL98EOzX8xLL5kJvwoyIlIA3HoH4CVLlnDnnXfi5eWVeS0tLQ2Xy0WJEiVISUnJ8r2caAdgERulppozlcaMMfvI1KpldvJt0cLuykTEzXnMDsDt2rXju+++y3LtoYceol69egwdOvSiQUZEbHTgAHTvDl9/bdo9esCbb4K/v711iYjHcesw4+/vT0RERJZrZcqUoUKFCtmui4gbWbwYHnnEzJMpWxamTTPBRkSkELh1mBERhzl1CgYNMrv3ghlOmjfPDC+JiBQSx4WZNWvW2F2CiORk1y5zQOT//gcuFwwdaubKeHvbXZmIeDjHhRkRcTOWBW+8AU89BWfOQGgozJljll6LiBQBhRkRuXR//AEPPQSff27akZEwc6bZDE9EpIi49T4zIuLGVqyAhg1NkPHxMb0zn36qICMiRU5hRkTy58wZMx+mfXs4csScpxQbC/37m7kyIiJFTMNMIpJ3+/aZSb4Zx4v07QsTJkDp0vbWJSLFmnpmRCRv5syBxo1NkClfHj7+2OwfoyAjIjZTz4yIXFhiIjz2GHzwgWm3bQtz50KVKvbWJSLy/9QzIyK527zZ9MZ88AF4ecELL8DKlQoyIuJW1DMjItmlpcH48TBypDkssnp1s5Nvq1Z2V+bx0tItYuOOczQpmUr+vrQIC8KrhCZWi1yIwoyIZHXoEPTsCatWmfZ998H06VCunK1lFRR3DgvLdsczOmYv8QnJmddCA30ZFRlOx4hQGysTcW8KMyLyj5gYswnesWNQpozZO+bBBz1mybU7h4Vlu+PpN3c71nnXjyQk02/udqZ1b2J7jSLuSnNmRAROnzb7xNx2mwkyTZrA9u0m2HhQkOk3d3uWIAP/hIVlu+Ntqsz0Fo2O2ZstyACZ10bH7CUtPac7RERhRqS427PHnG795pum/cQTsGED1K1rb10FyN3DQmzc8Wwh61wWEJ+QTGzc8aIrSsRBFGZEiivLMnNhmjWD3bshOBiWLYNXXzXHE3gQdw8LR5Nyr+1S7hMpbjRnRqQ4OnYMHnkEliwx7Y4dYdYsE2g8kLuHhUr+vgV6n0hxo54ZkeJmzRq45hoTZLy9YeJEc1ikhwYZcP+w0CIsiNBAX3KbneTCTFRuERZUlGWJOIbCjEhxcfYsjBgBN91kll9fdZXZFG/wYCjh2f8UuHtY8CrhYlRkeGYt58poj4oMd5sl5CLuxrP/BRMRIy4O2rSBsWPNXJmHH4Zt28zuvsWAE8JCx4hQpnVvQkhg1t6hkEBfLcsWuQiXZVkevdYvMTGRwMBAEhISCAgIsLsckaI3f7453ToxEQIDYcYMuPdeu6uyhTvvM5PBnTf1EylK+fn8VpgR8VQnT8Ljj5uJvWCOIpg3zxxNUIwpLIg4Q34+v7WaScQTbdsGXbvCTz+Z+TAjRsBzz0FJ/S/vVcJFy1oV7C5DRAqQ/mUT8STp6TBpEgwfbib8VqliTrxu08buykRECo3CjIinOHIEevWC5ctN+6674O23IUjLeUXEs2k1k4gn+PJLs3fM8uXg5wdvvQWLFinIiEixoJ4ZESdLSYFhw2DyZNNu2NCsXgoPt7UsEZGipDAj4lQ//GAm+e7YYdoDBsDLL4OvtrwXkeJFYUbEaSwLZs404eXUKahYEd57D2691e7KRERsoTAj4iQnTsCjj8JHH5n2zTfD++9DqHts+CYiYgdNABZxim++MZN8P/rI7Bfz8svw1VcKMiJS7KlnRsTdpaaaM5XGjDH7yNSqZSb5Nm9ud2UiIm5BYUbEnR04AA88AOvXm3bPnjBlCvj721uXiIgb0TCTiLtatMgMK61fb8LL3Lkwe7aCjIjIedQzI+JuTp2CQYPM7r0ALVqYAyJr1bK1LBERd6WeGRF3smsXNGtmgozLZc5YWr9eQUZE5ALUMyPiDiwL3ngDnnoKzpwxK5TmzoWbbrK7MhERt6cwI2K3P/6Ahx6Czz837chIsylexYr21iUi4hAaZhKx04oV5jylzz8HHx+zUunTTxVkRETyQWFGxA5nzsDTT0P79nDkCNSvD1u2QFSUmSsjIiJ5pmEmkaK2b585IHLrVtPu1w8mTAA/P3vrEhFxKPXMiBQVyzLnKDVubIJMUBB88glMnaogIyJyGdQzI1IUEhNND8y8eabdtq1ZrVSlir11iYh4APXMiBS2TZugUSMTZLy84MUXYeVKBRkRkQKinhmRwpKWZk62HjnS/LpGDRNoWra0uzIREY+iMCNSGA4dgh49YPVq077/fpg+HQID7a1LRMQDaZhJpKB99pnZO2b1aihTBt57z/TIKMiIiBQK9cyIFJTTp81xBG++adpNmsD8+VC3rr11iYh4OPXMiBSEPXvM6dYZQeaJJ2DjRgUZEZEi4NZhJjo6mubNm+Pv70+lSpW44447+OGHH+wuS+QflgXTppmTrnfvhuBgWLYMXn0VSpWyuzoRkWLBrcPM2rVriYqKYtOmTaxYsYLU1FTat2/P33//bXdpInDsGNx1Fzz2GCQnQ6dO8O230KGD3ZWJiBQrLsuyLLuLyKs//viDSpUqsXbtWtq0aZOnxyQmJhIYGEhCQgIBAQGFXKEUG2vWQPfuZtVSqVJmCfaAAVDCrX8+EBFxjPx8fjtqAnBCQgIAQUFBud6TkpJCSkpKZjsxMbHQ65Ji5OxZeP55iI42Q0xXXWUm+TZubHdlIiLFlmN+jLQsiyFDhnDdddcRERGR633R0dEEBgZmflWtWrUIqxSPFhcHbdrAuHEmyDzyCGzbpiAjImIzxwwzRUVF8fnnn7N+/XqqXGAb+Jx6ZqpWraphJrk88+dD377mjKXAQHj7bbjnHrurEhHxWB43zPT444/z2WefsW7dugsGGQAfHx98fHyKqDLxeElJ8PjjMHu2abduDR98ANWr21uXiIhkcuthJsuy6N+/Px9//DGrVq0iLCzM7pKkONm61Wx8N3u2mdg7cqSZ+KsgIyLiVty6ZyYqKop58+bx6aef4u/vz5EjRwAIDAzEz8/P5urEY6Wnw8SJ8MwzZsJv1aqmN+b66+2uTEREcuDWc2ZcLleO19977z0efPDBPD2HlmZLvhw5Ar16wfLlpv3vf5v5MeXL21uXiEgx4zFzZtw4Z4kn+uILePBB+OMP8POD114zK5ZyCdUiIuIe3DrMiBSJlBQYNgwmTzbthg1hwQK4+mpbyxIRkbxx6wnAIoXu++/hX//6J8gMGACbNyvIiIg4iHpmpHiyLHj3XRg4EE6dgooVYdYs6NLF7spERCSfFGak+PnrL3j0UVi0yLRvvhnefx9CQ+2tS0RELomGmaR4Wb8eGjUyQaZkSRg/Hr76SkFGRMTB1DMjxUNqKowdC2PGmH1katc2RxQ0a2Z3ZSIicpkUZsQjpaVbxMYd52hSMlWS/qTJM/1xrV9vvtmzJ0yZAv7+9hYpIiIFQmFGPM6y3fGMjtlLfEIynb5fz0vL3sCV8jepZcpScsZb0K2b3SWKiEgBUpgRj7Jsdzz95m7H90wy0Stn0PVbs5PvztC6DLjtaZ5peCMd8/mc5/byVPL3pUVYEF4ltJGeiIi7UJgRj5GWbjE6Zi/1jv7CG5+Op/bx30jHxbR/3c2k6x4gzasko2P2ckt4SJ7DyLm9PBlCA30ZFRlOxwhNGhYRcQdazSQeI/aXY3RcuZAl7w+h9vHfOFI2iAfuf5FX2vYi1askFhCfkExs3PE8PV9GL8+5QQbgSEIy/eZuZ9nu+EL4XYiISH4pzIhnOHqUsIfuY9TKt/FJS2VF7Wvp9NAbbKx+TfZbk5JzeIKsMnp5cjodLOPa6Ji9pKXr/DAREbtpmEmcb8UK6NmTkCNHSPHy5oWbHmFu4865HhBZyd/3ok8ZG3c8W4/Muc7t5WlZq8KlVi4iIgVAYUac68wZGDECXnkFAKt+fR5uN5Bv/CrneLsLCAk0E3gvJi+9N/m5T0RECo+GmcSZfvoJWrfODDL064dryxa6/+dWwASXc2W0R0WG52nyb156b/Jzn4iIFB6FGXEWy4LZs6FxY9i6FYKC4JNPYOpU8POjY0Qo07o3ISQwa8gICfRlWvcmeV6B1CIsiNBA32yhKIMLs6opL708IiJSuDTMJM6RkAD9+pljCABuuAHmzIEqVbLc1jEilFvCQy5rbxivEi5GRYbTb+52XJBlInB+e3lERKRwuSzL8ujlGImJiQQGBpKQkEBAQIDd5cil2rTJ7NwbFwdeXuaMpaFDza8LkfaZERGxR34+v9UzI+4tLQ1efhlGjjS/rlED5s2Dli2L5OULopfH02hHZBFxNwoz4r4OHYLu3WHNGtPu2hWmTYPAwCItw6uES8uv/596qkTEHWkCsLinTz+Fhg1NkClTBmbNgg8+KPIgI//Qjsgi4q4UZsS9nD4NUVFwxx1w/Dg0bQrbt0OvXrlugieFTzsii4g7U5gR97F7N7RoYZZZAzz5JGzYAHXr2luX5GtHZBGRoqY5M2I/yzJzYZ54ApKTITgY3n8f2re3uzL5f9oRWUTcmcKM2OvYMXj4YTNHBqBTJzM/plIlW8uSrLQjsoi4Mw0ziX1WrzaTfD/9FEqVgkmTYOlSBRk3pB2RRcSdKcxI0Tt7Fp59Ftq1g8OH4aqrSNuwkY2RPfj023g2/nxME0ndTMaOyHD5516JiBQ0DTNJ0frlF7OT7+bNpv3II6z4zzBGLt9PfMI/S3u1d4n7yTj36vx9ZkL0ZyUiNtNxBlJ05s2Dvn0hKcnsF/P22yy7+jr6zd2ebclvxs/3+TkcUoqGdgAWkaKg4wzEvSQlQf/+ZoUSQOvW8MEHpFWtxuiXV+W6d4kLs3fJLeEh+rB0I9oRWUTcjebMSOHauhWaNDFBpkQJGDXK7Opbvbr2LhERkQKhnhkpHOnpMGECPPMMpKZC1armOILrr8+8RXuXiIhIQVCYkYIXH2+OH1ixwrT//W+YMQOCsi7b1d4lIiJSEDTMJAXriy/gmmtMkPHzMyHmo4+yBRnQ3iUiIlIwFGakYKSkwKBB0KUL/PGHCTTbtsF//pPrAZHau0RERAqCwoxcvv/9D669Fl57zbQHDIBNm+Dqqy/60Iy9S0ICsw4lhQT6alm2iIjkiebMyKWzLHjnHRg4EE6fxqpYke+jX+fHZm2odOhvWoT55KlXpWNEKLeEh2jvEhERuSQKM3Jp/voLHn0UFi0C4M9/Xc+DN/Rn974ysG8nkL9dfLV3iYiIXCoNM0n+rV9v5sQsWgQlS/L9kBG0aPMUu60yWW47kpBMv7nbWbY7PpcnEhERuXwKM5J3qanw/PPQti0cPAi1a5P2zQYeqngD6a7sf5UydvYdHbNXB0eKiEihUZiRvPn1V7jhBhg92myI17MnbN9ObIWa2sVXRERspTAjF/fRR2ZY6ZtvwN/f7OQ7ezb4+2sXXxERsZ0mAEvu/v7brFR6913TbtEC5s+HmjUzb9EuviIiYjf1zEjOdu6Epk1NkHG5YPhwM/H3nCAD2sVXRETspzAjWVkWTJ5sNsH74QeoXBn++18YNw68vbPdrl18RUTEbgoz8o+jR+HWW2HwYDhzBm67DXbtgptuuuDDtIuviIjYSXNmxFi+3Jx0feQI+PjAxInQr1+u5yqdT7v4ioiIXRzRMzN16lTCwsLw9fWladOmfP3113aX5DnOnIGnnoIOHUyQqV8ftmyBxx7Lc5DJkLGL7+2NrqRlrQoKMiIiUiTcPswsXLiQQYMG8eyzz7Jjxw6uv/56OnXqxIEDB+wuzfl++glatYJXXzXtfv1MkGnQwN66RERE8sFlWZZbb8167bXX0qRJE6ZNm5Z57eqrr+aOO+4gOjr6oo9PTEwkMDCQhIQEAgICCrNU57Ass09M//5m+XVQkFm1dMcddlcmIiIC5O/z2617Zs6cOcO2bdto3759luvt27dnw4YNNlXlcAkJ0K0bPPSQCTI33GAm+SrIiIiIQ7n1BOA///yTtLQ0goODs1wPDg7myJEjOT4mJSWFlJSUzHZiYmKh1ugomzZB166wfz94ecGYMTB0qPm1iIiIQ7l1z0wG13kTUS3LynYtQ3R0NIGBgZlfVatWLYoS3VtaGowdC9ddZ4JMWJjZAO+ZZxRkRETE8dw6zFSsWBEvL69svTBHjx7N1luTYfjw4SQkJGR+HTx4sChKdV+//QY33wwjRphQ07Ur7NgB//qX3ZWJiIgUCLcOM6VKlaJp06asWLEiy/UVK1bQqlWrHB/j4+NDQEBAlq9ia8kSc0DkmjVQpgzMmmUOiQwMtLkwERGRguPWc2YAhgwZQo8ePWjWrBktW7ZkxowZHDhwgL59+9pdmvs6fRqGDIHp0027aVOYNw/q1rW3LhERkULg9mHmvvvu49ixY4wZM4b4+HgiIiL44osvqF69ut2luafvvjNDSXv2mPaTT5r5MqVK2VuXiIhIIXH7fWYuV2HtM5OWbrnX1v2WBVOnwhNPQEoKBAfD++/DecvaRUREnCA/n99u3zPjjpbtjmd0zF7iE5Izr4UG+jIqMtyeQxX//BMefhg++8y0O3eG996DSpWKvhYREZEi5tYTgN3Rst3x9Ju7PUuQATiSkEy/udtZtju+aAtavdpM8v3sMzOUNHkyLF2qICMiIsWGwkw+pKVbjI7ZS07jchnXRsfsJS29CEbuzp41+8S0aweHD8NVV8HmzTBwYL4PiBQREXEyhZl8iI07nq1H5lwWEJ+QTGzc8cIt5Jdf4PrrITrazJV55BHYtg0aNSrc1xUREXFDmjOTD0eTcg8yl3LfJVmzBm67DZKSoFw5ePttuPvuwns9ERERN6cwkw+V/H0L9L5L0qABBASYeTIffADVqhXea4mIiDiAwkw+tAgLIjTQlyMJyTnOm3EBIYFmmXahqVAB1q6F6tWhpP74RERENGcmH7xKuBgVGQ6Y4HKujPaoyPDC32+mVi0FGRERkf+nMJNPHSNCmda9CSGBWYeSQgJ9mda9iT37zIiIiBRj+vH+EnSMCOWW8BD32gFYRESkmFKYuUReJVy0rFXB7jJERESKPQ0ziYiIiKMpzIiIiIijKcyIiIiIoynMiIiIiKMpzIiIiIijKcyIiIiIoynMiIiIiKMpzIiIiIijKcyIiIiIoynMiIiIiKN5/HEGlmUBkJiYaHMlIiIiklcZn9sZn+MX4vFhJikpCYCqVavaXImIiIjkV1JSEoGBgRe8x2XlJfI4WHp6OocPH8bf3x+XyzNOtU5MTKRq1aocPHiQgIAAu8txNL2XBUfvZcHRe1lw9F4WnKJ+Ly3LIikpicqVK1OixIVnxXh8z0yJEiWoUqWK3WUUioCAAP3PWUD0XhYcvZcFR+9lwdF7WXCK8r28WI9MBk0AFhEREUdTmBERERFHU5hxIB8fH0aNGoWPj4/dpTie3suCo/ey4Oi9LDh6LwuOO7+XHj8BWERERDybemZERETE0RRmRERExNEUZkRERMTRFGZERETE0RRmHGbq1KmEhYXh6+tL06ZN+frrr+0uyZGio6Np3rw5/v7+VKpUiTvuuIMffvjB7rIcLzo6GpfLxaBBg+wuxbEOHTpE9+7dqVChAqVLl6ZRo0Zs27bN7rIcJzU1lREjRhAWFoafnx81a9ZkzJgxpKen212a21u3bh2RkZFUrlwZl8vFkiVLsnzfsiyef/55KleujJ+fHzfccAN79uyxp9j/pzDjIAsXLmTQoEE8++yz7Nixg+uvv55OnTpx4MABu0tznLVr1xIVFcWmTZtYsWIFqamptG/fnr///tvu0hxry5YtzJgxg4YNG9pdimP99ddftG7dGm9vb7788kv27t3LhAkTKFeunN2lOc7LL7/M9OnTmTJlCv/73/8YP348r7zyCm+88Ybdpbm9v//+m2uuuYYpU6bk+P3x48czceJEpkyZwpYtWwgJCeGWW27JPAvRFpY4RosWLay+fftmuVavXj1r2LBhNlXkOY4ePWoB1tq1a+0uxZGSkpKsOnXqWCtWrLDatm1rDRw40O6SHGno0KHWddddZ3cZHqFLly5W7969s1y76667rO7du9tUkTMB1ieffJLZTk9Pt0JCQqyXXnop81pycrIVGBhoTZ8+3YYKDfXMOMSZM2fYtm0b7du3z3K9ffv2bNiwwaaqPEdCQgIAQUFBNlfiTFFRUXTp0oWbb77Z7lIc7bPPPqNZs2bcc889VKpUicaNG/P222/bXZYjXXfddaxcuZIff/wRgF27drF+/Xo6d+5sc2XOFhcXx5EjR7J8Fvn4+NC2bVtbP4s8/qBJT/Hnn3+SlpZGcHBwluvBwcEcOXLEpqo8g2VZDBkyhOuuu46IiAi7y3GcBQsWsG3bNrZu3Wp3KY73yy+/MG3aNIYMGcIzzzxDbGwsAwYMwMfHh549e9pdnqMMHTqUhIQE6tWrh5eXF2lpaYwdO5auXbvaXZqjZXze5PRZ9Ouvv9pREqAw4zgulytL27KsbNckf/r378+3337L+vXr7S7FcQ4ePMjAgQNZvnw5vr6+dpfjeOnp6TRr1oxx48YB0LhxY/bs2cO0adMUZvJp4cKFzJ07l3nz5lG/fn127tzJoEGDqFy5Mr169bK7PMdzt88ihRmHqFixIl5eXtl6YY4ePZotIUvePf7443z22WesW7eOKlWq2F2O42zbto2jR4/StGnTzGtpaWmsW7eOKVOmkJKSgpeXl40VOktoaCjh4eFZrl199dUsXrzYpoqc66mnnmLYsGHcf//9ADRo0IBff/2V6OhohZnLEBISApgemtDQ0Mzrdn8Wac6MQ5QqVYqmTZuyYsWKLNdXrFhBq1atbKrKuSzLon///nz88cesWrWKsLAwu0typHbt2vHdd9+xc+fOzK9mzZrxwAMPsHPnTgWZfGrdunW2LQJ+/PFHqlevblNFznXq1ClKlMj6Eefl5aWl2ZcpLCyMkJCQLJ9FZ86cYe3atbZ+FqlnxkGGDBlCjx49aNasGS1btmTGjBkcOHCAvn372l2a40RFRTFv3jw+/fRT/P39M3u8AgMD8fPzs7k65/D39882z6hMmTJUqFBB848uweDBg2nVqhXjxo3j3nvvJTY2lhkzZjBjxgy7S3OcyMhIxo4dS7Vq1ahfvz47duxg4sSJ9O7d2+7S3N7JkyfZt29fZjsuLo6dO3cSFBREtWrVGDRoEOPGjaNOnTrUqVOHcePGUbp0abp162Zf0bato5JL8uabb1rVq1e3SpUqZTVp0kRLiS8RkOPXe++9Z3dpjqel2ZcnJibGioiIsHx8fKx69epZM2bMsLskR0pMTLQGDhxoVatWzfL19bVq1qxpPfvss1ZKSordpbm91atX5/jvY69evSzLMsuzR40aZYWEhFg+Pj5WmzZtrO+++87Wml2WZVk25SgRERGRy6Y5MyIiIuJoCjMiIiLiaAozIiIi4mgKMyIiIuJoCjMiIiLiaAozIiIi4mgKMyIiIuJoCjMiIiLiaAozIiIi4mgKMyIiIuJoCjMi4ih//PEHISEhjBs3LvPa5s2bKVWqFMuXL7exMhGxi85mEhHH+eKLL7jjjjvYsGED9erVo3HjxnTp0oXJkyfbXZqI2EBhRkQcKSoqiv/+9780b96cXbt2sWXLFnx9fe0uS0RsoDAjIo50+vRpIiIiOHjwIFu3bqVhw4Z2lyQiNtGcGRFxpF9++YXDhw+Tnp7Or7/+anc5ImIj9cyIiOOcOXOGFi1a0KhRI+rVq8fEiRP57rvvCA4Otrs0EbGBwoyIOM5TTz3FokWL2LVrF2XLluXGG2/E39+fpUuX2l2aiNhAw0wi4ihr1qxh8uTJzJkzh4CAAEqUKMGcOXNYv34906ZNs7s8EbGBemZERETE0dQzIyIiIo6mMCMiIiKOpjAjIiIijqYwIyIiIo6mMCMiIiKOpjAjIiIijqYwIyIiIo6mMCMiIiKOpjAjIiIijqYwIyIiIo6mMCMiIiKOpjAjIiIijvZ//fB56lIM7a8AAAAASUVORK5CYII=\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 训练\n",
    "for step in range(5000):\n",
    "    # 调用一次run_optimization就更新一次W,B\n",
    "    run_optimization()\n",
    "    # 展示一下训练过程\n",
    "    # 每100次训练, 输出一下过程\n",
    "    if step % 100 == 0:\n",
    "        pred = linear_regression(x)\n",
    "        loss = mean_square_loss(pred, y)\n",
    "        print(f'step:{step + 1}, loss: {loss}, W: {W.numpy()}, B:{B.numpy()}')\n",
    "        \n",
    "        if step == 0 or step == 4900:  # 绘制起始和结束时的拟合线\n",
    "            y_pred = linear_regression(x_test)\n",
    "            plt.scatter(x, y)\n",
    "            plt.plot(x_test, y_pred, c='r')\n",
    "            plt.xlabel('x')\n",
    "            plt.ylabel('y')\n",
    "            plt.title(f'Linear Regression - Step {step+1}')\n",
    "            plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T13:43:03.812788Z",
     "start_time": "2022-01-21T13:43:03.794836Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1.02865183])"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "linear.coef_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-21T13:43:16.282959Z",
     "start_time": "2022-01-21T13:43:16.273983Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-0.38284364614107513"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "linear.intercept_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 作业: 课后完成使用tensorflow实现逻辑斯蒂回归."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
